#include "store.h"
#include "string.h"
#include "spi.h"
#include "stdio.h"
#include "display.h"
#include "app_rdtss.h"
#include "ctrl.h"

#define  ERR_PARAM                  1
#define  ERR_NO_FREE_PSIZE          2
#define  ERR_INDEX_CONFLICT         3   
#define  ERR_PROCESS                4   
#define  ERR_PIC_ORDER              5   
#define  ERR_PIC_INCOMPLETE         6   




struct sector_t
{
    uint16_t voidf;
    uint16_t usedf;
    uint16_t index;
    uint16_t pcs_n;
};   

struct creat_moive_t
{
    uint16_t index;
    uint16_t pics_num;
    uint16_t next_pcs;
    uint16_t cur_sect;
    uint16_t cur_offset;
};

struct creat_moive_t crt_mov;



struct movs_ctrl_t movs;



void (*const_dislay_array[CONST_MAX])(void) = 
{
    display_heart,
    display_heart2,  
    0,
};
uint8_t user_display_flag = 0;
uint8_t user_display_num =0;



const uint8_t tr_map[57] = 
{
              03,04,05,06,07,
        20,19,18,17,16,15,14,13,12,
        23,24,25,26,27,28,29,30,31,
     43,42,41,40,39,38,37,36,35,34,33,
        45,46,47,48,49,50,51,52,53,
        64,63,62,61,60,59,58,57,56,
              69,70,71,72,73
};


//0x8000 
//0x10000 0x40000
uint8_t strat_store_process = 0;


struct store_pic_t store_pic;
void store_pics(uint8_t * pics, uint16_t length)
{
    printf("len =%d\r\n", length);
    printf("tag = %x\r\n", pics[0]);
    printf("num = %x\r\n", (pics[1] + pics[2] *256));
    printf("keep_time = %x\r\n", pics[3]);

//    uint16_t  wr_len = length - 4;
    uint8_t*  wr_ptr = pics + 4;
    store_pic.picn = (pics[1] + pics[2] *256);
    store_pic.time = pics[3];
    for(int i = 0; i<LED_NUM; i++)
    {
        if(i< 57)
        {    
            store_pic.data[i*3+0] = REG8(wr_ptr+ tr_map[i]*3 +0);
            store_pic.data[i*3+1] = REG8(wr_ptr+ tr_map[i]*3 +1);
            store_pic.data[i*3+2] = REG8(wr_ptr+ tr_map[i]*3 +2);   
        }
        else
        {
            store_pic.data[i*3+0] = REG8(wr_ptr+ tr_map[i-57]*3 + 77*3  +0);
            store_pic.data[i*3+1] = REG8(wr_ptr+ tr_map[i-57]*3 + 77*3  +1);
            store_pic.data[i*3+2] = REG8(wr_ptr+ tr_map[i-57]*3 + 77*3  +2);  
        }
    }
    Qflash_Write(crt_mov.cur_sect*0x1000+START_AREA +  crt_mov.cur_offset, (uint8_t *)&store_pic.picn, STORE_PIC_SIZE);
    crt_mov.cur_offset += STORE_PIC_SIZE;
    
    printf("DISPLAY index: %x\r\n", crt_mov.index);
    for(int i = 0; i<SECTION_NUM_AREA; i++)
    {
        printf("VOIDF[%i] =%x\r\n", i, SECTOR_VOIDF(i));
        if(SECTOR_VOIDF(i) == VOIDF_IND)
        {    
            printf("INDEX[%i] =%x\r\n", i, SECTOR_INDEX(i));
            if(SECTOR_INDEX(i) == crt_mov.index)
            {
                printf("SECT[0x%05x] INDEX:%x PCS_N:%x\r\n", i*0x10000, SECTOR_INDEX(i), SECTOR_PCS_N(i));
                for(int j = 0; j<11; j++)
                {
                    printf("SECTOR_PIC_NO =%x\r\n", SECTOR_PIC_ND(i, j));
                    if(SECTOR_PIC_ND(i, j) != 0xFFFF)
                    {    
                        printf("picture[%d] time %x\r\n", SECTOR_PIC_ND(i, j),  SECTOR_PIC_TD(i, j) );
                        // uint8_t * tmp_data = SECTOR_PIC_DA(i, j);
                        // for(int k = 0; k<LED_NUM*3; k++)
                        // {
                        //     if( (k%16) == 0)
                        //     {
                        //         printf("\r\n");
                        //     }    
                        //     printf("%02x ", tmp_data[k]);
                        // }
                        // printf("\r\n");
                        return;
                    }    
                }
            } 
        }            
    }
    printf("ENDD\r\n");
}   




void update_movs_index(void)
{ 
    printf("UPDATE_MOVS_INDEX\r\n");
    memset(&movs.mov_index[0], 0xFF, 0x20);
    movs.free_pics = 0;
    uint16_t t_free_pics  = 0;
    for(int i =0; i<SECTION_NUM_AREA; i++)
    {        
        if(SECTOR_VOIDF(i) !=  VOIDF_IND)
        {
            continue;
        }

        if(SECTOR_USEDF(i) != USEDF_FRE)  
        {
            uint8_t found = false;
            for(int j = 0; j<16; j++)
            {
                if(movs.mov_index[j] == SECTOR_INDEX(i))
                {
                    printf("found:\r\n");
                    found = true;
                    break;
                }    
            }
            if(found == false)
            {    
                for(int j = 0; j<16; j++)
                {
                    if(movs.mov_index[j] == 0xFFFF)
                    {
                        movs.mov_index[j] = SECTOR_INDEX(i);
                        break;
                    }    
                }
            }         
        }
        else
        {
            t_free_pics += 11;
        }    
    }
    movs.free_pics = t_free_pics;
     
    printf("free_pics =%d\r\n", movs.free_pics);
    
    printf("sector_usedf list:\r\n");
    for(int i = 0; i<SECTION_NUM_AREA; i++)
    {
        if(SECTOR_USEDF(i) != USEDF_FRE)
        {    
            printf("[0x%05x]:Void:%x Used:%x Index:%x\r\n", i*0x1000, SECTOR_VOIDF(i), SECTOR_USEDF(i), SECTOR_INDEX(i));
        }    
    }
    
    printf("index list:\r\n");
    for(int i = 0; i<16; i++)
    {
        if(movs.mov_index[i] != 0xFFFF)
        {
            printf("[%i]:%x \t", i, movs.mov_index[i]);
        }    
    }
    printf("index list end\r\n");
}

void clear_void_sector(void)
{
    for(int i =0; i<SECTION_NUM_AREA; i++)
    {
        // printf("try clear sector %d\r\n", i);
        if(SECTOR_VOIDF(i) != VOIDF_IND)
        {
            printf("do clear sector %d\r\n", i);
            Qflash_Erase_Sector(SECTOR_VOIDDF(i));
        }
    }
}

void store_init(void)
{  
    printf("STORE_INIT\r\n");

    clear_void_sector();
    
    update_movs_index();
   
    movs.cur_index = 0;
    
    printf("IF movs.mov_index[0]:%x then start mov\r\n", movs.mov_index[0]);
   if(movs.mov_index[0] != 0xFFFF && REG32(USER_RESET_REG) == USER_RESET_WORK_BY_BT)
   {
       printf("START_MOV\r\n");
       user_display_flag = 1;
       mov_act(movs.mov_index[0]);
   }
   else
    {
        printf("than play the 1st animation\r\n");
        user_display_flag = 0;
        user_display_num = 0;
        const_dislay_array[0]();
    }
}

void void_n_sector(uint8_t i)
{
    uint8_t void_fd[2] = {0x11, 0x22};
    Qflash_Write(SECTOR_VOIDDF(i),  &void_fd[0],  2);
}    

uint8_t del_movs(uint16_t index)
{
    uint8_t status = 0;

    for(int i =0; i<SECTION_NUM_AREA; i++)
    {
        if(index == 0xFFFF)
        {
            if(SECTOR_USEDF(i) != 0xFFFF)
            {
                 if(SECTOR_VOIDF(i) == VOIDF_IND)
                 {
                    //SECTOR_VOIDF(i) = VOIDF_VOD;
                    void_n_sector(i);
                 }    
            }    
        }    
        else if(SECTOR_INDEX(i) == index)
        {
            if(SECTOR_VOIDF(i) == VOIDF_IND)
            {
                void_n_sector(i);
            }    
        }    
    }
    
    update_movs_index();
    return status;
}

uint16_t  seek_free_sector(void)
{
    /// seek for the point 
    for(int i=0; i<SECTION_NUM_AREA; i++)
    {
        if(SECTOR_USEDF(i) == USEDF_FRE)
        {
             return i;
        }    
    }
    return 0;
}  

void  start_new_sector(void)
{
    printf("start_new_sector\r\n");
    crt_mov.cur_offset = 2;
    crt_mov.cur_sect = seek_free_sector();

    printf("crt_mov.index =%x\r\n", crt_mov.index);
    printf("crt_mov.pics_num =%x\r\n", crt_mov.pics_num);
    printf("crt_mov.next_pcs =%x\r\n", crt_mov.next_pcs);
    printf("crt_mov.cur_sect =%x\r\n",  crt_mov.cur_sect);
    printf("crt_mov.cur_offset =%x\r\n", crt_mov.cur_offset);
    
    uint8_t init_store[6] = {0x33, 0x22, crt_mov.index & 0xFF, (crt_mov.index >> 8) & 0xFF, crt_mov.pics_num & 0xFF, (crt_mov.pics_num >> 8) & 0xFF};
    /// fillin usedf index pcsn
    Qflash_Write(crt_mov.cur_sect*0x1000+START_AREA +  crt_mov.cur_offset,  init_store,  6);
    crt_mov.cur_offset += 6;
    update_movs_index(); 
}    

static uint8_t reverseBits(uint8_t c)
{
    uint8_t result = 0;

    for (int i = 0; i < 8; i++) {
        result = (result << 1) | (c & 1);
        c >>= 1;
    }

    return result;
}

uint8_t ble_get_end_tag_flag = 0;
extern void set_flag_reset_work(void);
extern void ns_ble_disconnect(void);
void ble_store_cb(uint8_t * data, uint16_t length)
{
    uint8_t cmd = data[0];
    printf("ble_store_cb %02x %02x %02x %02x %02x , length = %d\r\n", data[0], data[1], data[2], data[3], data[4], length);
    if(cmd == INIT_TAG)
    {
        ble_get_end_tag_flag = 0;
        printf("INIT_TAG\r\n");

        uint16_t index = data[1] + data[2]*256;
        uint16_t pcsn = data[3] + data[4]*256;
        printf("index = %x\r\n", index);
        printf("pcsn = %x\r\n", pcsn);

        uint8_t status = NO_ERROR;
        
        if(length != 5)
        {
            status = ERR_PARAM;
        }    
        
        /// check the same index;
        for(int i = 0; i<16; i++)
        {
            if(movs.mov_index[i] == index)
            {
                printf("ERR ERR_INDEX_CONFLICT movs.mov_index[%i] =%x index =%x\r\n",i, movs.mov_index[i], index);
                status = ERR_INDEX_CONFLICT ;
                break;
            }    
        }
        
        if(strat_store_process)
        {
            printf("ERR then void all_download_data then memset crt_mov\r\n");
            status = ERR_PROCESS;
            
            del_movs(crt_mov.index);
        } 
        
        if(pcsn > movs.free_pics)
        {
            printf("ERR no free size\r\n");
            status = ERR_NO_FREE_PSIZE;
        }

        light_on_led_num(0);

        memset(&crt_mov.index, 0, sizeof(struct creat_moive_t));
        
        if(!status)
        {   
            strat_store_process = 1;

            crt_mov.index = index;
            crt_mov.pics_num = pcsn;            
            crt_mov.next_pcs  = 0;     
            
            start_new_sector(); 
        }
        else
        {
            strat_store_process = 0;
        }    
        
        uint8_t event[2] = {0x81, status};
        rdtss_send_notify(event, 2);
    }
    else if(cmd == PICS_TAG)
    {
        GPIO_SetBits(GPIOB, GPIO_PIN_12);
        ble_get_end_tag_flag = 0;
        printf("PICS_TAG\r\n");
        uint8_t status = NO_ERROR;
        uint16_t cur_pcs = data[1] + data[2]*256;
        //printf("length = %d, STORE_PIC_SIZE =%d\r\n", length, STORE_PIC_SIZE);
        if(length != 466)
        {
            status = ERR_PARAM;
            del_movs(crt_mov.index);
        } 
        
        if(strat_store_process == 0)
        {
            printf("ERR then void all_download_data then memset crt_mov\r\n");
            status = ERR_PROCESS;
            
            del_movs(crt_mov.index);
        } 
        
        
        for(int i = 4; i < length; i++) {
            if(data[i] > 0)
                data[i] = reverseBits(data[i]);
        }
        
        if( (cur_pcs != crt_mov.next_pcs) || (cur_pcs >= crt_mov.pics_num))
        {
            printf("ERR cur_pcs = %x next_pcs = %x pics_num =%x\r\n", cur_pcs, crt_mov.next_pcs, crt_mov.pics_num);
            status = ERR_PIC_ORDER;
            del_movs(crt_mov.index);
        }
        if(status == NO_ERROR)
            light_on_led_num(cur_pcs+1);

        if(!status)
        {
            crt_mov.next_pcs++;
            
            if( (crt_mov.cur_offset + STORE_PIC_SIZE) > 0x1000)
            {
                start_new_sector();                
            }
            store_pics(data, length);
        }
        uint8_t event[4] = {PICS_EVT, status, 0, 0}; //TODOCRC
        rdtss_send_notify(event, 4);
    }
    else if(cmd == END_TAG)
    {
        printf("END_TAG\r\n");
        uint8_t status = NO_ERROR;
        //defer to void flash
        if(crt_mov.next_pcs != crt_mov.pics_num)
        {
            status  = ERR_PIC_INCOMPLETE;
            del_movs(crt_mov.index);
        } 
        
        if(strat_store_process == 0)
        {
            printf("ERR then void all_download_data then memset crt_mov\r\n");
            status = ERR_PROCESS;
            
            del_movs(crt_mov.index);
        } 
        
        uint8_t event[2] = {END_EVT, status};
        rdtss_send_notify(event, 2);
        
        strat_store_process = 0;
        printf("status =%x\r\n", status);
        ble_get_end_tag_flag = 1;
        ns_ble_disconnect();
        // if(!status)
        // {    
        //     mov_act(crt_mov.index);
        // }
    }  
    else if(cmd == DEL_TAG)
    {
        GPIO_ResetBits(GPIOB, GPIO_PIN_12);
        ble_get_end_tag_flag = 0;
        printf("DEL_TAG\r\n");
        uint8_t status  = NO_ERROR;
        if(length != 3)
        {
            status = ERR_PARAM;
        }
        else
        {    
            uint16_t index = data[1] + data[2]*256;
            status = del_movs(index);
        }
        uint8_t event[2] = {DEL_EVT, status};
        rdtss_send_notify(event, 2);
    }
    else if(cmd == INFO_TAG)
    {
        printf("INFO_TAG\r\n");
        update_movs_index();
        
        uint8_t status  = NO_ERROR;
        uint8_t event[42] = {DEL_EVT, status};
        uint8_t count = 0;
        for(int i = 0; i<10; i++)
        {
            if(movs.mov_index[i] ==0xFFFF)
            {
                break;
            }    
            count++;
            event[i*4+0+2] = movs.mov_index[i] &0xFF;
            event[i*4+1+2] = (movs.mov_index[i]>>8) &0xFF ;
            for(int i =0; i<SECTION_NUM_AREA; i++)
            {
                if((SECTOR_VOIDF(i) == VOIDF_IND) && (SECTOR_USEDF(i) != USEDF_FRE))
                {
                    if(SECTOR_INDEX(i) == movs.mov_index[i])
                    {
                        uint16_t dp_mov_pcsn = SECTOR_PCS_N(i);
                        event[i*4+2+2] = dp_mov_pcsn &0xFF;
                        event[i*4+3+2] = (dp_mov_pcsn>>8) &0xFF ;
                        break;
                    }    
                }    
            }
        }
        rdtss_send_notify(event, 2+count*4);
    }
    else if(cmd == TEST_MODE)
    {
        user_display_flag = 2;
    }
}    
